package com.miaosha.demo.controller;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.miaosha.demo.config.AccessLimit;
import com.miaosha.demo.exception.GlobalException;
import com.miaosha.demo.pojo.Order;
import com.miaosha.demo.pojo.SeckillMessage;
import com.miaosha.demo.pojo.SeckillOrder;
import com.miaosha.demo.pojo.User;
import com.miaosha.demo.rabbitmq.MQSender;
import com.miaosha.demo.service.IGoodsService;
import com.miaosha.demo.service.IOrderService;
import com.miaosha.demo.service.ISeckillOrderService;
import com.miaosha.demo.utils.JsonUtil;
import com.miaosha.demo.vo.GoodsVo;
import com.miaosha.demo.vo.RespBean;
import com.miaosha.demo.vo.RespBeanEnum;
import com.wf.captcha.ArithmeticCaptcha;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Controller
@RequestMapping("/seckill")
public class SecKillController implements InitializingBean {


    @Autowired
    private IGoodsService goodsService;
    @Autowired
    private ISeckillOrderService seckillOrderService;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private RedisTemplate<String,Object>redisTemplate;

    @Autowired
    private MQSender mqSender;
    @Autowired
    private RedisScript<Long> script;

    private Map<Long,Boolean>EmptyStockMap=new HashMap<>();

    @RequestMapping("/doSeckill2")
    public String doSeckill2(Model model, User user,Long goodsId){
        System.out.println("进入秒杀页面");
        if(user==null)
            return "login";
        GoodsVo goodsVo =
                goodsService.findGoodsByGoodsId(goodsId);
        if(goodsVo.getStockCount()<1) {
            model.addAttribute("errmsg",RespBeanEnum.EMPTY_STOCK.getMessage());
            return "secKillFail";
        }
//        SeckillOrder seckillOrder =
//                seckillOrderService.getOne(new QueryWrapper<SeckillOrder>()
//                .eq("user_id", user.getId())
//                .eq("goods_id", goodsId));
        SeckillOrder seckillOrder=(SeckillOrder) redisTemplate
                .opsForValue()
                .get("order:"+user.getId()+":"+goodsId);
        if(seckillOrder!=null)
        {
            model.addAttribute("errmsg",RespBeanEnum.REPEATE_ERROR
                    .getMessage());
            return "secKillFail";
        }
        Order order= orderService.seckill(user,goodsVo);
        model.addAttribute("order",order);
        model.addAttribute("goods",goodsVo);
        return "orderDetail";
    }

    /*
     * 优化前QPS:89
     * 优化后QPS:644:
     * */
    @RequestMapping(value = "{path}/doSeckill",method = RequestMethod.POST)
    @ResponseBody
    public RespBean doSeckill(@PathVariable String path, Model model, User user, Long goodsId){
        if(user==null)
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        ValueOperations valueOperations=redisTemplate.opsForValue();
        boolean check=orderService.checkPath(user,goodsId,path);
        if(!check){
            return RespBean.error(RespBeanEnum.REQUEST_ILLEGAL);
        }
        SeckillOrder seckillOrder=(SeckillOrder)redisTemplate
                .opsForValue()
                .get("order:"+user.getId()+":"+goodsId);
        if(seckillOrder!=null){
            return RespBean.error(RespBeanEnum.REPEATE_ERROR);
        }
        if(EmptyStockMap.get(goodsId))
        {
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }
//        Long stock =
//                valueOperations.decrement("seckillGoods:" + goodsId);
        Long stock = redisTemplate.execute(script,
                Collections.singletonList("seckillGoods:" + goodsId),
                Collections.EMPTY_LIST);
        if(stock<0){
            EmptyStockMap.put(goodsId,true);
            valueOperations.increment("seckillGoods:"+goodsId);
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }
        SeckillMessage seckillMessage = new SeckillMessage(user,goodsId);
        mqSender.sendSeckillMessage(JsonUtil.object2JsonStr(seckillMessage));
        return RespBean.success(0);
        /*GoodsVo goodsVo =
                goodsService.findGoodsByGoodsId(goodsId);
        if(goodsVo.getStockCount()<1) {
            model.addAttribute("errmsg",RespBeanEnum.EMPTY_STOCK.getMessage());
            return RespBean.error(RespBeanEnum.EMPTY_STOCK);
        }
        SeckillOrder seckillOrder =
                seckillOrderService.getOne(new QueryWrapper<SeckillOrder>()
                        .eq("user_id", user.getId())
                        .eq("goods_id", goodsId));
        if(seckillOrder!=null)
        {
            model.addAttribute("errmsg",RespBeanEnum.REPEATE_ERROR
                    .getMessage());
            return RespBean.error(RespBeanEnum.REPEATE_ERROR);
        }
        Order order= orderService.seckill(user,goodsVo);
        return RespBean.success(order);*/
    }
    @RequestMapping(value = "/result",method = RequestMethod.GET)
    @ResponseBody
    public RespBean result(User user,Long goodsId){
        if(user==null){
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        Long orderId=seckillOrderService.getResult(user,goodsId);
        return RespBean.success(orderId);
    }



    @AccessLimit(second=5,maxCount=5,needLogin=true)
    @RequestMapping(value = "/path",method = RequestMethod.GET)
    @ResponseBody
    public RespBean getPath(User user,
                            Long goodsId,
                            String captcha,
                            HttpServletRequest request){
        if(user==null){
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        boolean check=orderService.checkCaptcha(user,goodsId,captcha);
        if(!check){
            return RespBean.error(RespBeanEnum.CAPTCHA_ERROR);
        }
        String str=orderService.createPath(user,goodsId);
        return RespBean.success(str);
    }



    @RequestMapping(value = "/captcha",method = RequestMethod.GET)
    public void verifyCode(User user, Long goodsId, HttpServletResponse response){
        if(user==null||goodsId<0)
            throw new GlobalException(RespBeanEnum.REQUEST_ILLEGAL);
        response.setContentType("image/jpg");
        response.setHeader("Param","No-cache");
        response.setHeader("Cache-Control","no-cache");
        response.setDateHeader("Expires",0);
        ArithmeticCaptcha captcha =
                new ArithmeticCaptcha(130, 32, 3);
        redisTemplate.opsForValue().set("captcha:"+user.getId()+":"+goodsId,
                captcha.text(),300, TimeUnit.SECONDS);
        try {
            captcha.out(response.getOutputStream());
        }catch (IOException e){
            log.error("验证码生成失败",e.getMessage());
        }
    }


    /*初始化时候执行的方法*/
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVo> lsit = goodsService.findGoodsVo();
        if(CollectionUtils.isEmpty(lsit)){
            return;
        }
        lsit.forEach(goodsVo -> {
            redisTemplate.opsForValue().set("seckillGoods:"+goodsVo.getId(),
                    goodsVo.getStockCount());
            EmptyStockMap.put(goodsVo.getId(),false);
        });
    }
}
